#include "mmap_output_strategy.h"

#include <algorithm>
#include <cerrno>
#include <cstring>
#include <fcntl.h> 
#include <stdexcept>
#include <syslog.h> 
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "system_log_error_code.h"

namespace Base {
namespace SystemLog {
MMapOutputStrategy::MMapOutputStrategy(const MMapOutputOptions &options)
    : FileOutputStrategy(options), mmapOptions_(options)
{
    if (mmapOptions_.mappingSize == 0) {
        throw std::invalid_argument("Mapping size must be positive");
    }
}

MMapOutputStrategy::~MMapOutputStrategy()
{
    Close();
}

ErrCode MMapOutputStrategy::OpenFile()
{
    auto err = FileOutputStrategy::OpenFile();
    if (err != ERR_OK) {
        return err;
    }

    // 获取文件大小
    struct stat st;
    if (fstat(fileDescriptor_, &st) != 0) {
        return ERR_FILE_STAT_FAILED;
    }
    
    currentOffset_ = static_cast<size_t>(st.st_size);
    return RemapFile(mmapOptions_.mappingSize);
}

ErrCode MMapOutputStrategy::CloseCurrentFile() {
    if (mappedAddress_) {
        DoFlush();
        munmap(mappedAddress_, mappedSize_);
        mappedAddress_ = nullptr;
        mappedSize_ = 0;
    }

    // 将文件截断到实际写入的大小
    if (fileDescriptor_ >= 0 && currentOffset_ > 0) {
        if (ftruncate(fileDescriptor_, static_cast<off_t>(currentOffset_)) != 0) {
            syslog(LOG_ERR, "Failed to truncate file to actual size: %s", strerror(errno));
            return ERR_MMAP_CLOSE_CURRENT_FILE;
        }
    }
    currentOffset_ = 0;
    return FileOutputStrategy::CloseCurrentFile();
}

ErrCode MMapOutputStrategy::Write(const char* data, size_t len)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (fileDescriptor_ < 0) {
        return ERR_FILE_NOT_OPEN;
    }
    
    auto err = RollFileIfNeeded(len);
    if (err != ERR_OK) {
        return err;
    }
    
    // 检查映射空间是否足够
    if (currentOffset_ + len > mappedSize_) {
        err = RemapFile(std::max(mmapOptions_.mappingSize, currentOffset_ + len));
        if (err != ERR_OK) {
            return err;
        }
    }
    
    // 内存复制
    char* dest = static_cast<char*>(mappedAddress_) + currentOffset_;
    memcpy(dest, data, len);
    currentOffset_ += len;
    currentSize_ += len;
    
    return ERR_OK;
}

ErrCode MMapOutputStrategy::Flush()
{
    std::lock_guard<std::mutex> lock(mutex_);
    return DoFlush();
}

ErrCode MMapOutputStrategy::Close()
{
    std::lock_guard<std::mutex> lock(mutex_);
    return CloseCurrentFile();
}

ErrCode MMapOutputStrategy::RemapFile(size_t requiredSize)
{
    if (fileDescriptor_ < 0) {
        syslog(LOG_ERR, "File not open for mmap remapping");
        return ERR_FILE_NOT_OPEN;
    }

    // 直接释放旧映射，不进行同步
    // 因为在多线程环境中，同步操作可能导致访问已失效的内存
    if (mappedAddress_ && mappedAddress_ != MAP_FAILED) {
        munmap(mappedAddress_, mappedSize_);
        mappedAddress_ = nullptr;
        mappedSize_ = 0;
    }

    // 扩展文件
    if (ftruncate(fileDescriptor_, static_cast<off_t>(requiredSize)) != 0) {
        syslog(LOG_ERR, "Failed to truncate file for mmap: %s", strerror(errno));
        return ERR_FILE_TRUNCATE_FAILED;
    }
    
    // 创建新映射
    mappedAddress_ = mmap(nullptr, requiredSize, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor_, 0);
    
    if (mappedAddress_ == MAP_FAILED) {
        syslog(LOG_ERR, "Failed to mmap file: %s", strerror(errno));
        mappedAddress_ = nullptr;
        return ERR_MMAP_FAILED;
    }
    
    mappedSize_ = requiredSize;
    return ERR_OK;
}

ErrCode MMapOutputStrategy::DoFlush() {
    // 额外的安全检查
    if (!mappedAddress_ || mappedAddress_ == MAP_FAILED || currentOffset_ == 0 || mappedSize_ == 0) {
        return ERR_OK;
    }
    
    // 确保刷新的大小不会超过映射的大小
    size_t flushSize = std::min(currentOffset_, mappedSize_);
    
    if (msync(mappedAddress_, flushSize, MS_SYNC) != 0) {
        syslog(LOG_ERR, "Failed to sync mmap file: %s", strerror(errno));
        return ERR_IO_WRITE_FAILED;
    }
    return ERR_OK;
}
} // namespace SystemLog
} // namespace Base